package cn.edu.nit.sys.service.impl;

import cn.edu.nit.sys.entity.*;
import cn.edu.nit.sys.export.StudentExport;
import cn.edu.nit.sys.export.StudentImport;
import cn.edu.nit.sys.export.SubjectImport;
import cn.edu.nit.sys.export.UserExport;
import cn.edu.nit.sys.mapper.FileMapper;
import cn.edu.nit.sys.mapper.StudentMapper;
import cn.edu.nit.sys.mapper.SubjectMapper;
import cn.edu.nit.sys.mapper.UserMapper;
import cn.edu.nit.sys.service.FileService;
import cn.edu.nit.sys.utils.R;
import cn.edu.nit.sys.utils.Utils;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.listener.PageReadListener;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.OSSException;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.mysql.cj.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ResourceUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @Author xiaobai
 * @Date 2023/3/18 18:57
 * @Version 1.0.0
 */
@Service
@Slf4j
public class FileServiceImpl implements FileService {

    @Autowired
    private FileMapper fileMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private StudentMapper studentMapper;

    @Autowired
    private SubjectMapper subjectMapper;

    @Override
    @Transactional
    public R uploadFile(MultipartFile image, String uid, String type, String waterText) {
        String path = null;
        try {
            path = ResourceUtils.getFile("classpath:static").toString();
        } catch (FileNotFoundException e) {
            log.error("获取地址失败：e", e);
        }
        String prefixPath = "image/";
        String prefix = UUID.randomUUID().toString();
        String attachId = image.getOriginalFilename();
        String attachName = prefix + ".png";
        if("avatar".equals(type)) {
            prefixPath = "avatar/system/";
        }else if("sign".equals(type)) {
            prefixPath = "sign/";
        }else if("leave".equals(type)) {
            prefixPath = "leave/";
        }else if("forum".equals(type)) {
            prefixPath = "forum/";
        }

        String objectName = prefixPath + attachName;;
        path = path + "/" + prefixPath.substring(0, prefixPath.length() - 1);
        if(StringUtils.isNullOrEmpty(uid)) {
            return R.error("禁止匿名上传文件，请先登陆");
        }
        objectName = prefixPath + uid + "/" + attachName;
        path = path + "/" + uid;
        log.info("路径：{}", path);
        File file = new File(path);
        if(!file.exists()) {
            file.mkdirs();
        }
        try {
            image.transferTo(new File( path + "/" + attachName));
            if("forum".equals(type)) {
                Utils.addWaterMark(path + "/" + attachName, waterText);
            }
        }catch (Exception e) {
            e.printStackTrace();
            return R.error("上传失败");
        }
        JSONObject map = new JSONObject();
        String downUrl = "/static/" + objectName;
        Integer integer = fileMapper.saveImageInfo(prefix, attachId, downUrl, uid, type);
        if (integer > 0) {
            map.put("id", prefix);
            map.put("downUrl", downUrl);
            map.put("attachId", attachId);
        }
        return R.ok("上传成功", map);
    }

    @Override
    public R getSysAvatar() {
        QueryWrapper<Files> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("type", "avatar");
        queryWrapper.orderByDesc("create_time");
        List<Files> files = fileMapper.selectList(queryWrapper);
        return R.ok(files);
    }

    @Override
    public void exportExcel(String type, HttpServletResponse response) {
        String fileName = "";
        String path = "";
        try {
            path = ResourceUtils.getFile("classpath:static") + "/excel/export";
            File file = new File(path);
            if(!file.exists()) {
                file.mkdirs();
            }
            Date date = new Date();
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH-mm-ss");
            String time = dateFormat.format(date);
            if("user".equals(type)) {
                fileName = "/用户名单-"+ time + ".xlsx";
                path += fileName;
                List<UserExport> data = fileMapper.getAllUser();
                doWrite(path, UserExport.class, time, data);
            }else if("teacher".equals(type)) {
                fileName = "/教室名单-" + time + ".xlsx";
                path += fileName;
                List<Teacher> data = fileMapper.getAllTeacher();
                doWrite(path, UserExport.class, time, data);
            }else if("student".equals(type)) {
                fileName = "/学生名单-" + time + ".xlsx";
                path += fileName;
                List<Student> data = fileMapper.getAllStudent();
                doWrite(path, StudentExport.class, time, data);
            }
            download(fileName, response);
        } catch (FileNotFoundException e) {
            log.error("获取地址失败", e);
        }
    }

    @Override
    public void downloadExcel(String fileName, HttpServletResponse response) {
        downloadExcel(fileName, response);
    }

    @Override
    @Transactional
    public R importData(MultipartFile excel, String uid, String type) {
        String path = "";
        String attachName = "";
        try {
            path = ResourceUtils.getFile("classpath:static") + "/excel/import/" + type;
            File file = new File(path);
            if(!file.exists()) {
                file.mkdirs();
            }
            attachName = UUID.randomUUID().toString() + ".xlsx";
            excel.transferTo(new File(path + "/" + attachName));
            fileMapper.saveImageInfo(UUID.randomUUID().toString(), excel.getOriginalFilename(),
                    "/static/excel/export" + attachName, uid, type);
            doRead(path + "/" + attachName, type);
        } catch (Exception e) {
            File file = new File(path + "/" + attachName);
            if(file.exists()) {
                file.delete();
            }
            log.info("文件上传失败，{}", e);
            return R.error("文件上传失败");
        }
        return R.ok("导入成功");
    }

    @Override
    public R delSysAvatar(String id) {
        int rs = fileMapper.delSysAvatar(id);
        return rs > 0 ? R.ok("删除成功") : R.error("删除失败");
    }

    private void download(String filePath, HttpServletResponse response) {
        FileInputStream fileInputStream = null;
        InputStream fis = null;
        OutputStream outputStream = null;
        try {
            File file = new File(ResourceUtils.getFile("classpath:static") + "/excel/export" + filePath);
            // 将文件写入输入流
            fileInputStream = new FileInputStream(file);
            fis = new BufferedInputStream(fileInputStream);
            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            fis.close();
            response.reset();
            String[] split = filePath.split("/");
            String name = split[split.length - 1];
            // 解决跨域问题
            response.addHeader("Access-Control-Allow-Origin", "*");
            response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
            response.setHeader("FileName", URLEncoder.encode(name + ".xlsx", "UTF-8"));
            response.setHeader("Access-Control-Expose-Headers", "FileName");
            response.setCharacterEncoding("UTF-8");
            response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(name, "UTF-8"));
            response.addHeader("Content-Length", "" + file.length());
            outputStream = new BufferedOutputStream(response.getOutputStream());
            response.setContentType("application/octet-stream");
            outputStream.write(buffer);
            outputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
            log.error("文件下载异常，{}", e);
        } finally {
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * Excel文件导出
     * @param path  文件存放路径
     * @param tClass  导出实体类
     * @param date  时间
     * @param data  数据集
     */
    private void doWrite(String path, Class<?> tClass, String date, List<?> data) {
        try {
            EasyExcel.write(path, tClass).sheet(date).doWrite(data);
        } catch (Exception e) {
            log.error("文件写入失败", e);
            File file = new File(path);
            file.delete();
        }
    }

    /**
     * 读取表格文件
     * @param path  文件路径
     * @param type  业务类型
     */
    private void doRead(String path, String type) {
        if("student".equals(type)) {
            EasyExcel.read(path, StudentImport.class, new PageReadListener<StudentImport>(dataList -> {
                for(StudentImport studentImport : dataList) {
                    addStudent(studentImport);
                }
            })).sheet().doRead();
        }else if("subject".equals(type)) {
            EasyExcel.read(path, SubjectImport.class, new PageReadListener<SubjectImport>(dataList -> {
                for(SubjectImport subjectImport : dataList) {
                    Subject subject = new Subject();
                    subject.setName(subjectImport.getName());
                    subject.setTeacherId(subjectImport.getTeacherId());
                    subject.setTeacher(subjectImport.getTeacher());
                    subject.setClazz(subjectImport.getClazz());
                    subject.setDuration(subjectImport.getDuration());
                    subject.setTimeStr(subjectImport.getTime());
                    subject.setScore(subjectImport.getScore());
                    subject.setGrade(subjectImport.getGrade());
                    subjectMapper.insert(subject);
                }
            })).sheet().doRead();
        }
    }

    /**
     * 学生信息插入数据库
     * @param studentImport 表格数据
     * @return
     */
    private int addStudent(StudentImport studentImport) {
        int rs = 0;
        User user = new User();
        Student student = new Student();
        String lastStudentId = studentMapper.getLastStudentId();
        String userId = UUID.randomUUID().toString().replaceAll("\\-", "");

        student.setDeptId(studentMapper.getDeptId(studentImport.getDept()));
        student.setMajorId(studentMapper.getMajorId(studentImport.getMajor()));
        student.setClazz(studentImport.getClazz());
        student.setUid(userId);
        student.setName(studentImport.getName());
        student.setSex((Integer.parseInt(studentImport.getIdCard().substring(17)) % 2) + "");
        StringBuilder sb = new StringBuilder(studentImport.getIdCard().substring(7, 15));
        sb.insert(6, "-");
        sb.insert(4, "-");
        student.setBirth(sb.toString());
        String year = Calendar.getInstance().get(Calendar.YEAR) + "";
        student.setGrade(year);
        if(lastStudentId.substring(0, 4).equals(year)) {
            student.setId(Integer.parseInt(lastStudentId) + 1 + "");
        }else {     // 首位新生
            student.setId(year + "100001");
        }

        user.setId(userId);
        String nickName = "新用户" + Utils.generateLettersAndNumbers();
        user.setNickname(nickName);
        user.setUsername(student.getId());
        user.setPassword(studentImport.getIdCard().substring(13));
        user.setRoleId(14);
        if(userMapper.insert(user) > 0) {
            rs = studentMapper.insert(student);
        }
        return rs;
    }
}
